home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / vim / src / edit.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  32KB  |  1,296 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Read the file "credits.txt" for a list of people who contributed.
  6.  * Read the file "uganda.txt" for copying and usage conditions.
  7.  */
  8.  
  9. /*
  10.  * edit.c: functions for insert mode
  11.  */
  12.  
  13. #include "vim.h"
  14. #include "globals.h"
  15. #include "proto.h"
  16. #include "param.h"
  17. #include "ops.h"    /* for operator */
  18.  
  19. extern char_u *get_inserted();
  20. static void start_arrow __ARGS((void));
  21. static void stop_arrow __ARGS((void));
  22. static void stop_insert __ARGS((void));
  23. static int echeck_abbr __ARGS((int));
  24.  
  25. int arrow_used;                /* Normally FALSE, set to TRUE after hitting
  26.                              * cursor key in insert mode. Used by vgetorpeek()
  27.                              * to decide when to call u_sync() */
  28. int restart_edit = 0;        /* call edit when next command finished */
  29. static char_u    *last_insert = NULL;
  30.                             /* the text of the previous insert */
  31. static int        last_insert_skip;
  32.                             /* number of chars in front of the previous insert */
  33. static int        new_insert_skip;
  34.                             /* number of chars in front of the current insert */
  35.  
  36.     void
  37. edit(count)
  38.     long count;
  39. {
  40.     int             c;
  41.     int             cc;
  42.     char_u        *ptr;
  43.     char_u        *saved_line = NULL;        /* saved line for replace mode */
  44.     linenr_t     saved_lnum = 0;        /* lnum of saved line */
  45.     int             saved_char = NUL;        /* char replaced by NL */
  46.     linenr_t     lnum;
  47.     int          temp = 0;
  48.     int             mode;
  49.     int             nextc = 0;
  50.     int             lastc = 0;
  51.     colnr_t         mincol;
  52.     static linenr_t o_lnum = 0;
  53.     static int     o_eol = FALSE;
  54. #ifdef WEBB_KEYWORD_COMPL
  55.     FPOS         complete_pos;
  56.     FPOS         first_match;
  57.     char_u         *complete_pat = NULL;
  58.     char_u         *completion_str = NULL;
  59.     char_u         *last_completion_str = NULL;
  60.     char_u         *tmp_ptr;
  61.     int             previous_c = 0;
  62.     int             complete_col = 0;            /* init for gcc */
  63.     int             complete_direction;
  64.     int             complete_any_word = 0;        /* true -> ^N/^P hit with no prefix
  65.                                              * init for gcc */
  66.     int             done;
  67.     int             found_error = FALSE;
  68.     char_u         backup_char = 0;            /* init for gcc */
  69.  
  70.     c = NUL;
  71. #endif /* WEBB_KEYWORD_COMPL */
  72.  
  73.     if (restart_edit)
  74.     {
  75.         arrow_used = TRUE;
  76.         restart_edit = 0;
  77.         /*
  78.          * If the cursor was after the end-of-line before the CTRL-O
  79.          * and it is now at the end-of-line, put it after the end-of-line
  80.          * (this is not correct in very rare cases).
  81.          */
  82.         if (o_eol && curwin->w_cursor.lnum == o_lnum &&
  83.                 *((ptr = ml_get(curwin->w_cursor.lnum)) + curwin->w_cursor.col) != NUL &&
  84.                 *(ptr + curwin->w_cursor.col + 1) == NUL)
  85.             ++curwin->w_cursor.col;
  86.     }
  87.     else
  88.     {
  89.         arrow_used = FALSE;
  90.         o_eol = FALSE;
  91.     }
  92.  
  93. #ifdef DIGRAPHS
  94.     dodigraph(-1);                    /* clear digraphs */
  95. #endif
  96.  
  97. /*
  98.  * Get the current length of the redo buffer, those characters have to be
  99.  * skipped if we want to get to the inserted characters.
  100.  */
  101.  
  102.     ptr = get_inserted();
  103.     new_insert_skip = STRLEN(ptr);
  104.     free(ptr);
  105.  
  106.     old_indent = 0;
  107.  
  108.     for (;;)
  109.     {
  110.         if (arrow_used)        /* don't repeat insert when arrow key used */
  111.             count = 0;
  112.  
  113.         if (!arrow_used)
  114.             curwin->w_set_curswant = TRUE;    /* set curwin->w_curswant for next K_DARROW or K_UARROW */
  115.         cursupdate();        /* Figure out where the cursor is based on curwin->w_cursor. */
  116.         showruler(0);
  117.         setcursor();
  118. #ifdef WEBB_KEYWORD_COMPL
  119.         previous_c = c;
  120. #endif /* WEBB_KEYWORD_COMPL */
  121.         if (nextc)            /* character remaining from CTRL-V */
  122.         {
  123.             c = nextc;
  124.             nextc = 0;
  125.         }
  126.         else
  127.         {
  128.             c = vgetc();
  129.             if (c == Ctrl('C'))
  130.                 got_int = FALSE;
  131.         }
  132. #ifdef WEBB_KEYWORD_COMPL
  133.         if (previous_c == Ctrl('N') || previous_c == Ctrl('P'))
  134.         {
  135.             /* Show error message from attempted keyword completion (probably
  136.              * 'Pattern not found') until another key is hit, then go back to
  137.              * showing what mode we are in.
  138.              */
  139.             showmode();
  140.             if (c != Ctrl('N') && c != Ctrl('P'))
  141.             {
  142.                 /* Get here when we have finished typing a sequence of ^N and
  143.                  * ^P. Free up memory that was used, and make sure we can redo
  144.                  * the insert.
  145.                  */
  146.                 if (completion_str != NULL)
  147.                     AppendToRedobuff(completion_str);
  148.                 free(complete_pat);
  149.                 free(completion_str);
  150.                 free(last_completion_str);
  151.                 complete_pat = completion_str = last_completion_str = NULL;
  152.             }
  153.         }
  154. #endif /* WEBB_KEYWORD_COMPL */
  155.         if (c != Ctrl('D'))            /* remember to detect ^^D and 0^D */
  156.             lastc = c;
  157.  
  158. /*
  159.  * In replace mode a backspace puts the original text back.
  160.  * We save the current line to be able to do that.
  161.  * If characters are appended to the line, they will be deleted.
  162.  * If we start a new line (with CR) the saved line will be empty, thus
  163.  * the characters will be deleted.
  164.  * If we backspace over the new line, that line will be saved.
  165.  */
  166.         if (State == REPLACE && saved_lnum != curwin->w_cursor.lnum)
  167.         {
  168.             free(saved_line);
  169.             saved_line = strsave(ml_get(curwin->w_cursor.lnum));
  170.             saved_lnum = curwin->w_cursor.lnum;
  171.         }
  172.  
  173. #ifdef DIGRAPHS
  174.         c = dodigraph(c);
  175. #endif /* DIGRAPHS */
  176.  
  177.         if (c == Ctrl('V'))
  178.         {
  179.             screen_start();
  180.             screen_outchar('^', curwin->w_row, curwin->w_col);
  181.             AppendToRedobuff((char_u *)"\026");    /* CTRL-V */
  182.             cursupdate();
  183.             setcursor();
  184.  
  185.             c = get_literal(&nextc);
  186.  
  187.             insertchar(c);
  188.             continue;
  189.         }
  190.         switch (c)        /* handle character in insert mode */
  191.         {
  192.               case Ctrl('O'):        /* execute one command */
  193.                 if (echeck_abbr(Ctrl('O') + 0x100))
  194.                     break;
  195.                   count = 0;
  196.                 if (State == INSERT)
  197.                     restart_edit = 'I';
  198.                 else
  199.                     restart_edit = 'R';
  200.                 o_lnum = curwin->w_cursor.lnum;
  201.                 o_eol = (gchar_cursor() == NUL);
  202.                 goto doESCkey;
  203.  
  204.               case ESC:             /* an escape ends input mode */
  205.                 if (echeck_abbr(ESC + 0x100))
  206.                     break;
  207.                 /*FALLTHROUGH*/
  208.  
  209.               case Ctrl('C'):
  210. doESCkey:
  211.                 if (!arrow_used)
  212.                 {
  213.                     AppendToRedobuff(ESC_STR);
  214.  
  215.                     if (--count > 0)        /* repeat what was typed */
  216.                     {
  217.                             (void)start_redo_ins();
  218.                             continue;
  219.                     }
  220.                     stop_insert();
  221.                 }
  222.                 if (!restart_edit)
  223.                     curwin->w_set_curswant = TRUE;
  224.  
  225.                 /*
  226.                  * The cursor should end up on the last inserted character.
  227.                  */
  228.                 if (curwin->w_cursor.col != 0 && (!restart_edit || gchar_cursor() == NUL) && !p_ri)
  229.                     dec_cursor();
  230.                 if (extraspace)            /* did reverse replace in column 0 */
  231.                 {
  232.                     (void)delchar(FALSE);
  233.                     updateline();
  234.                     extraspace = FALSE;
  235.                 }
  236.                 State = NORMAL;
  237.                     /* inchar() may have deleted the "INSERT" message */
  238.                 if (Recording)
  239.                     showmode();
  240.                 else if (p_smd)
  241.                     MSG("");
  242.                 free(saved_line);
  243.                 old_indent = 0;
  244.                 return;
  245.  
  246.                   /*
  247.                  * Insert the previously inserted text.
  248.                  * Last_insert actually is a copy of the redo buffer, so we
  249.                  * first have to remove the command.
  250.                  * For ^@ the trailing ESC will end the insert.
  251.                  */
  252.               case K_ZERO:
  253.               case Ctrl('A'):
  254.                 stuff_inserted(NUL, 1L, (c == Ctrl('A')));
  255.                 break;
  256.  
  257.                   /*
  258.                  * insert the contents of a register
  259.                  */
  260.               case Ctrl('R'):
  261.                   if (insertbuf(vgetc()) == FAIL)
  262.                     beep();
  263.                 break;
  264.  
  265.               case Ctrl('B'):            /* toggle reverse insert mode */
  266.                   p_ri = !p_ri;
  267.                 showmode();
  268.                 break;
  269.  
  270.                 /*
  271.                  * If the cursor is on an indent, ^T/^D insert/delete one
  272.                  * shiftwidth. Otherwise ^T/^D behave like a TAB/backspace.
  273.                  * This isn't completely compatible with
  274.                  * vi, but the difference isn't very noticeable and now you can
  275.                  * mix ^D/backspace and ^T/TAB without thinking about which one
  276.                  * must be used.
  277.                  */
  278.               case Ctrl('T'):        /* make indent one shiftwidth greater */
  279.               case Ctrl('D'):         /* make indent one shiftwidth smaller */
  280.                 stop_arrow();
  281.                 AppendCharToRedobuff(c);
  282.                 if ((lastc == '0' || lastc == '^') && curwin->w_cursor.col)
  283.                 {
  284.                     --curwin->w_cursor.col;
  285.                     (void)delchar(FALSE);            /* delete the '^' or '0' */
  286.                     if (lastc == '^')
  287.                         old_indent = get_indent();    /* remember current indent */
  288.  
  289.                         /* determine offset from first non-blank */
  290.                     temp = curwin->w_cursor.col;
  291.                     beginline(TRUE);
  292.                     temp -= curwin->w_cursor.col;
  293.                     set_indent(0, TRUE);    /* remove all indent */
  294.                 }
  295.                 else
  296.                 {
  297. ins_indent:
  298.                         /* determine offset from first non-blank */
  299.                     temp = curwin->w_cursor.col;
  300.                     beginline(TRUE);
  301.                     temp -= curwin->w_cursor.col;
  302.  
  303.                     shift_line(c == Ctrl('D'), TRUE, 1);
  304.  
  305.                         /* try to put cursor on same character */
  306.                     temp += curwin->w_cursor.col;
  307.                 }
  308.                 if (temp <= 0)
  309.                     curwin->w_cursor.col = 0;
  310.                 else
  311.                     curwin->w_cursor.col = temp;
  312.                 did_ai = FALSE;
  313.                 did_si = FALSE;
  314.                 can_si = FALSE;
  315.                   goto redraw;
  316.  
  317.               case BS:
  318.               case DEL:
  319. nextbs:
  320.                 mode = 0;
  321. dodel:
  322.                 /* can't delete anything in an empty file */
  323.                 /* can't backup past first character in buffer */
  324.                 /* can't backup past starting point unless 'backspace' > 1 */
  325.                 /* can backup to a previous line if 'backspace' == 0 */
  326.                 if (bufempty() || (!p_ri &&
  327.                         ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col <= 0) ||
  328.                         (p_bs < 2 && (arrow_used ||
  329.                             (curwin->w_cursor.lnum == Insstart.lnum &&
  330.                             curwin->w_cursor.col <= Insstart.col) ||
  331.                             (curwin->w_cursor.col <= 0 && p_bs == 0))))))
  332.                 {
  333.                     beep();
  334.                     goto redraw;
  335.                 }
  336.  
  337.                 stop_arrow();
  338.                 if (p_ri)
  339.                     inc_cursor();
  340.                 if (curwin->w_cursor.col <= 0)        /* delete newline! */
  341.                 {
  342.                     lnum = Insstart.lnum;
  343.                     if (curwin->w_cursor.lnum == Insstart.lnum || p_ri)
  344.                     {
  345.                         if (!u_save((linenr_t)(curwin->w_cursor.lnum - 2), (linenr_t)(curwin->w_cursor.lnum + 1)))
  346.                             goto redraw;
  347.                         --Insstart.lnum;
  348.                         Insstart.col = 0;
  349.                         /* this is in xvim, why?
  350.                         if (curbuf->b_p_ai)
  351.                             for (ptr = ml_get(Insstart.lnum);
  352.                                             iswhite(*ptr++); Insstart.col++)
  353.                                 ; */
  354.                     }
  355.                 /* in replace mode, in the line we started replacing, we
  356.                                                         only move the cursor */
  357.                     if (State != REPLACE || curwin->w_cursor.lnum > lnum)
  358.                     {
  359.                         temp = gchar_cursor();        /* remember current char */
  360.                         --curwin->w_cursor.lnum;
  361.                         (void)dojoin(FALSE, TRUE);
  362.                         if (temp == NUL && gchar_cursor() != NUL)
  363.                             ++curwin->w_cursor.col;
  364.                         if (saved_char)                /* restore what NL replaced */
  365.                         {
  366.                             State = NORMAL;            /* no replace for this char */
  367.                             inschar(saved_char);    /* but no showmatch */
  368.                             State = REPLACE;
  369.                             saved_char = NUL;
  370.                             if (!p_ri)
  371.                                 dec_cursor();
  372.                         }
  373.                         else if (p_ri)                /* in reverse mode */
  374.                             saved_lnum = 0;            /* save this line again */
  375.                     }
  376.                     else
  377.                         dec_cursor();
  378.                     did_ai = FALSE;
  379.                 }
  380.                 else
  381.                 {
  382.                     if (p_ri && State != REPLACE)
  383.                         dec_cursor();
  384.                     mincol = 0;
  385.                     if (mode == 3 && !p_ri && curbuf->b_p_ai)    /* keep indent */
  386.                     {
  387.                         temp = curwin->w_cursor.col;
  388.                         beginline(TRUE);
  389.                         if (curwin->w_cursor.col < temp)
  390.                             mincol = curwin->w_cursor.col;
  391.                         curwin->w_cursor.col = temp;
  392.                     }
  393.  
  394.                     /* delete upto starting point, start of line or previous word */
  395.                     do
  396.                     {
  397.                         if (!p_ri)
  398.                             dec_cursor();
  399.  
  400.                                 /* start of word? */
  401.                         if (mode == 1 && !isspace(gchar_cursor()))
  402.                         {
  403.                             mode = 2;
  404.                             temp = isidchar(gchar_cursor());
  405.                         }
  406.                                 /* end of word? */
  407.                         else if (mode == 2 && (isspace(cc = gchar_cursor()) || isidchar(cc) != temp))
  408.                         {
  409.                             if (!p_ri)
  410.                                 inc_cursor();
  411.                             else if (State == REPLACE)
  412.                                 dec_cursor();
  413.                             break;
  414.                         }
  415.                         if (State == REPLACE)
  416.                         {
  417.                             if (saved_line)
  418.                             {
  419.                                 if (extraspace)
  420.                                 {
  421.                                     if ((int)STRLEN(ml_get(curwin->w_cursor.lnum)) - 1 > (int)STRLEN(saved_line))
  422.                                         (void)delchar(FALSE);
  423.                                     else
  424.                                     {
  425.                                         dec_cursor();
  426.                                         (void)delchar(FALSE);
  427.                                         extraspace = FALSE;
  428.                                         pchar_cursor(*saved_line);
  429.                                     }
  430.                                 }
  431.                                 else if (curwin->w_cursor.col < STRLEN(saved_line))
  432.                                     pchar_cursor(saved_line[curwin->w_cursor.col]);
  433.                                 else if (!p_ri)
  434.                                     (void)delchar(FALSE);
  435.                             }
  436.                         }
  437.                         else  /* State != REPLACE */
  438.                         {
  439.                             (void)delchar(FALSE);
  440.                             if (p_ri && gchar_cursor() == NUL)
  441.                                 break;
  442.                         }
  443.                         if (mode == 0)        /* just a single backspace */
  444.                             break;
  445.                         if (p_ri && State == REPLACE && inc_cursor())
  446.                             break;
  447.                     } while (p_ri || (curwin->w_cursor.col > mincol && (curwin->w_cursor.lnum != Insstart.lnum ||
  448.                             curwin->w_cursor.col != Insstart.col)));
  449.                     if (extraspace)
  450.                         dec_cursor();
  451.                 }
  452.                 did_si = FALSE;
  453.                 can_si = FALSE;
  454.                 if (curwin->w_cursor.col <= 1)
  455.                     did_ai = FALSE;
  456.                 /*
  457.                  * It's a little strange to put backspaces into the redo
  458.                  * buffer, but it makes auto-indent a lot easier to deal
  459.                  * with.
  460.                  */
  461.                 AppendCharToRedobuff(c);
  462.                 if (vpeekc() == BS)
  463.                 {
  464.                         c = vgetc();
  465.                         goto nextbs;    /* speedup multiple backspaces */
  466.                 }
  467. redraw:
  468.                 cursupdate();
  469.                 updateline();
  470.                 break;
  471.  
  472.               case Ctrl('W'):        /* delete word before cursor */
  473.                   mode = 1;
  474.                   goto dodel;
  475.  
  476.               case Ctrl('U'):        /* delete inserted text in current line */
  477.                 mode = 3;
  478.                   goto dodel;
  479.  
  480.               case K_LARROW:
  481.                   if (oneleft() == OK)
  482.                 {
  483.                     start_arrow();
  484.                 }
  485.                     /* if 'whichwrap' set for cursor in insert mode may go
  486.                      * to previous line */
  487.                 else if ((p_ww & 16) && curwin->w_cursor.lnum > 1)
  488.                 {
  489.                     start_arrow();
  490.                     --(curwin->w_cursor.lnum);
  491.                     coladvance(MAXCOL);
  492.                     curwin->w_curswant = MAXCOL;    /* so we stay at the end */
  493.                 }
  494.                 else
  495.                     beep();
  496.                 break;
  497.  
  498.               case K_SLARROW:
  499.                   if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0)
  500.                 {
  501.                     bck_word(1L, 0);
  502.                     start_arrow();
  503.                 }
  504.                 else
  505.                     beep();
  506.                 break;
  507.  
  508.               case K_RARROW:
  509.                 if (gchar_cursor() != NUL)
  510.                 {
  511.                     curwin->w_set_curswant = TRUE;
  512.                     start_arrow();
  513.                     ++curwin->w_cursor.col;
  514.                 }
  515.                     /* if 'whichwrap' set for cursor in insert mode may go
  516.                      * to next line */
  517.                 else if ((p_ww & 16) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  518.                 {
  519.                     curwin->w_set_curswant = TRUE;
  520.                     start_arrow();
  521.                     ++curwin->w_cursor.lnum;
  522.                     curwin->w_cursor.col = 0;
  523.                 }
  524.                 else
  525.                     beep();
  526.                 break;
  527.  
  528.               case K_SRARROW:
  529.                   if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count || gchar_cursor() != NUL)
  530.                 {
  531.                     fwd_word(1L, 0, 0);
  532.                     start_arrow();
  533.                 }
  534.                 else
  535.                     beep();
  536.                 break;
  537.  
  538.               case K_UARROW:
  539.                   if (oneup(1L))
  540.                     start_arrow();
  541.                 else
  542.                     beep();
  543.                 break;
  544.  
  545.               case K_SUARROW:
  546.                   if (onepage(BACKWARD, 1L))
  547.                     start_arrow();
  548.                 else
  549.                     beep();
  550.                 break;
  551.  
  552.               case K_DARROW:
  553.                   if (onedown(1L))
  554.                     start_arrow();
  555.                 else
  556.                     beep();
  557.                 break;
  558.  
  559.               case K_SDARROW:
  560.                   if (onepage(FORWARD, 1L))
  561.                     start_arrow();
  562.                 else
  563.                     beep();
  564.                 break;
  565.  
  566.               case TAB:
  567.                 if (echeck_abbr(TAB + 0x100))
  568.                     break;
  569.                   if ((!curbuf->b_p_et && !(p_sta && inindent())) || (p_ri && State == REPLACE))
  570.                     goto normalchar;
  571.  
  572.                 AppendToRedobuff((char_u *)"\t");
  573.  
  574.                 if (!curbuf->b_p_et)                /* insert smart tab */
  575.                     goto ins_indent;
  576.  
  577.                                         /* p_te set: expand a tab into spaces */
  578.                 stop_arrow();
  579.                 did_ai = FALSE;
  580.                 did_si = FALSE;
  581.                 can_si = FALSE;
  582.                 if (p_sta && inindent())
  583.                     temp = (int)curbuf->b_p_sw;
  584.                 else
  585.                     temp = (int)curbuf->b_p_ts;
  586.                 temp -= curwin->w_cursor.col % temp;
  587.                 inschar(' ');            /* delete one char in replace mode */
  588.                 while (--temp)
  589.                     insstr((char_u *)" ");        /* insstr does not delete chars */
  590.                 goto redraw;
  591.  
  592.               case CR:
  593.               case NL:
  594.                 if (echeck_abbr(c + 0x100))
  595.                     break;
  596.                 stop_arrow();
  597.                 if (State == REPLACE)
  598.                 {
  599.                     saved_char = gchar_cursor();
  600.                     (void)delchar(FALSE);
  601.                 }
  602.                 /*
  603.                  * When 'autoindent' set delete white space after the cursor.
  604.                  * Vi does this, although it probably does it implicitly due
  605.                  * to the way it does auto-indent -- webb.
  606.                  */
  607.                 if (curbuf->b_p_ai || curbuf->b_p_si)
  608.                     while ((c = gchar_cursor()) == ' ' || c == TAB)
  609.                         (void)delchar(FALSE);
  610.  
  611.                 AppendToRedobuff(NL_STR);
  612.                 if (!Opencmd(FORWARD, TRUE, State == INSERT))
  613.                     goto doESCkey;        /* out of memory */
  614.                 if (p_ri)
  615.                 {
  616.                     dec_cursor();
  617.                     if (State == REPLACE && curwin->w_cursor.col > 0)
  618.                         dec_cursor();
  619.                 }
  620.                 break;
  621.  
  622. #ifdef DIGRAPHS
  623.               case Ctrl('K'):
  624.                 screen_start();
  625.                 screen_outchar('?', curwin->w_row, curwin->w_col);
  626.                 setcursor();
  627.                   c = vgetc();
  628.                 if (c != ESC)
  629.                 {
  630.                     if (charsize(c) == 1)
  631.                     {
  632.                         screen_start();
  633.                         screen_outchar(c, curwin->w_row, curwin->w_col);
  634.                     }
  635.                     setcursor();
  636.                     cc = vgetc();
  637.                     if (cc != ESC)
  638.                     {
  639.                         AppendToRedobuff((char_u *)"\026");    /* CTRL-V */
  640.                         c = getdigraph(c, cc, TRUE);
  641.                         goto normalchar;
  642.                     }
  643.                 }
  644.                 updateline();
  645.                 goto doESCkey;
  646. #endif /* DIGRAPHS */
  647.  
  648. #ifdef WEBB_KEYWORD_COMPL
  649.               case Ctrl('P'):            /* Do previous pattern completion */
  650.               case Ctrl('N'):            /* Do next pattern completion */
  651.                 if (c == Ctrl('P'))
  652.                     complete_direction = BACKWARD;
  653.                 else
  654.                     complete_direction = FORWARD;
  655.                 if (previous_c != Ctrl('N') && previous_c != Ctrl('P'))
  656.                 {
  657.                     /* First time we hit ^N or ^P (in a row, I mean) */
  658.                     complete_pos = curwin->w_cursor;
  659.                     ptr = ml_get(complete_pos.lnum);
  660.                     complete_col = complete_pos.col;
  661.                     temp = complete_col - 1;
  662.                     if (temp < 0 || !isidchar(ptr[temp]))
  663.                     {
  664.                         complete_pat = strsave((char_u *)"\\<[a-zA-Z_]");
  665.                         complete_any_word = TRUE;
  666.                     }
  667.                     else
  668.                     {
  669.                         while (temp >= 0 && isidchar(ptr[temp]))
  670.                             temp--;
  671.                         temp++;
  672.                         complete_pat = alloc(curwin->w_cursor.col - temp + 3);
  673.                         if (complete_pat != NULL)
  674.                             sprintf((char *)complete_pat, "\\<%.*s",
  675.                                 (int)(curwin->w_cursor.col - temp), ptr + temp);
  676.                         complete_any_word = FALSE;
  677.                     }
  678.                     last_completion_str = strsave((char_u *)" ");
  679.                 }
  680.                 else
  681.                 {
  682.                     /* This is not the first ^N or ^P we have hit in a row */
  683.                     while (curwin->w_cursor.col != complete_col)
  684.                     {
  685.                         curwin->w_cursor.col--;
  686.                         delchar(FALSE);
  687.                     }
  688.                     if (completion_str != NULL)
  689.                     {
  690.                         free(last_completion_str);
  691.                         last_completion_str = strsave(completion_str);
  692.                     }
  693.                 }
  694.                 if (complete_pat == NULL || last_completion_str == NULL)
  695.                 {
  696.                     found_error = TRUE;
  697.                     break;
  698.                 }
  699.                 if (!complete_any_word)
  700.                 {
  701.                     ptr = ml_get(curwin->w_cursor.lnum);
  702.                     backup_char = ptr[complete_col - 1];
  703.                     ptr[complete_col - 1] = ' ';
  704.                 }
  705.                 done = FALSE;
  706.                 found_error = FALSE;
  707.                 first_match.lnum = 0;
  708.                 keep_old_search_pattern = TRUE;
  709.                 while (!done)
  710.                 {
  711.                     if (complete_direction == BACKWARD)
  712.                     {
  713.                         ptr = ml_get(complete_pos.lnum);
  714.                         while (isidchar(ptr[complete_pos.col]))
  715.                             complete_pos.col--;
  716.                         complete_pos.col++;
  717.                     }
  718.                     if (!searchit(&complete_pos, complete_direction,
  719.                         complete_pat, 1L, TRUE, TRUE))
  720.                     {
  721.                         found_error = TRUE;
  722.                         break;
  723.                     }
  724.                     if (complete_any_word)
  725.                         ptr = ml_get_pos(&complete_pos);
  726.                     else
  727.                         ptr = ml_get_pos(&complete_pos) + 1;
  728.                     tmp_ptr = ptr;
  729.                     temp = 1;
  730.                     while (*tmp_ptr != NUL && isidchar(*tmp_ptr++))
  731.                         temp++;
  732.                     free (completion_str);
  733.                     tmp_ptr = completion_str = alloc(temp);
  734.                     if (completion_str == NULL)
  735.                     {
  736.                         found_error = TRUE;
  737.                         break;
  738.                     }
  739.                     while (*ptr != NUL && isidchar(*ptr))
  740.                         *(tmp_ptr++) = *(ptr++);
  741.                     *tmp_ptr = NUL;
  742.                     if (completion_str[0] != NUL &&
  743.                             STRCMP(completion_str, last_completion_str) != 0)
  744.                         done = TRUE;
  745.                     else if (first_match.lnum == 0)
  746.                     {
  747.                         first_match.lnum = complete_pos.lnum;
  748.                         first_match.col = complete_pos.col;
  749.                     }
  750.                     else if (complete_pos.lnum == first_match.lnum
  751.                          && complete_pos.col == first_match.col)
  752.                     {
  753.                         if (completion_str[0] == NUL)
  754.                             EMSG("Exact match only");
  755.                         else
  756.                             EMSG("No other matches");
  757.                         done = TRUE;
  758.                     }
  759.                 }
  760.                 if (!found_error)
  761.                     insstr(completion_str);
  762.                 if (!complete_any_word)
  763.                 {
  764.                     ptr = ml_get(curwin->w_cursor.lnum);
  765.                     ptr[complete_col - 1] = backup_char;
  766.                 }
  767.                 keep_old_search_pattern = FALSE;
  768.                 updateline();
  769.                 break;
  770. #endif /* WEBB_KEYWORD_COMPL */
  771.  
  772.               case Ctrl('Y'):                /* copy from previous line */
  773.                 lnum = curwin->w_cursor.lnum - 1;
  774.                 goto copychar;
  775.  
  776.               case Ctrl('E'):                /* copy from next line */
  777.                 lnum = curwin->w_cursor.lnum + 1;
  778. copychar:
  779.                 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
  780.                 {
  781.                     beep();
  782.                     break;
  783.                 }
  784.  
  785.                 /* try to advance to the cursor column */
  786.                 temp = 0;
  787.                 ptr = ml_get(lnum);
  788.                 while (temp < curwin->w_virtcol && *ptr)
  789.                         temp += chartabsize(*ptr++, (long)temp);
  790.  
  791.                 if (temp > curwin->w_virtcol)
  792.                         --ptr;
  793.                 if ((c = *ptr) == NUL)
  794.                 {
  795.                     beep();
  796.                     break;
  797.                 }
  798.  
  799.                 /*FALLTHROUGH*/
  800.               default:
  801. normalchar:
  802.                 /*
  803.                  * do some very smart indenting when entering '{' or '}' or '#'
  804.                  */
  805.                 if (curwin->w_cursor.col > 0 && ((can_si && c == '}') || (did_si && c == '{')))
  806.                 {
  807.                     FPOS    *pos, old_pos;
  808.                     int        i;
  809.  
  810.                         /* for '}' set indent equal to matching '{' */
  811.                     if (c == '}' && (pos = showmatch('{')) != NULL)
  812.                     {
  813.                         old_pos = curwin->w_cursor;
  814.                         curwin->w_cursor = *pos;
  815.                         i = get_indent();
  816.                         curwin->w_cursor = old_pos;
  817.                         set_indent(i, TRUE);
  818.                     }
  819.                     else
  820.                         shift_line(TRUE, TRUE, 1);
  821.                 }
  822.                     /* set indent of '#' always to 0 */
  823.                 if (curwin->w_cursor.col > 0 && can_si && c == '#')
  824.                 {
  825.                                 /* remember current indent for next line */
  826.                     old_indent = get_indent();
  827.                     set_indent(0, TRUE);
  828.                 }
  829.  
  830.                 if (isidchar(c) || !echeck_abbr(c))
  831.                     insertchar(c);
  832.                 break;
  833.             }
  834.     }
  835. }
  836.  
  837. /*
  838.  * Next character is interpreted literally.
  839.  * A one, two or three digit decimal number is interpreted as its byte value.
  840.  * If one or two digits are entered, *nextc is set to the next character.
  841.  */
  842.     int
  843. get_literal(nextc)
  844.     int *nextc;
  845. {
  846.     int             cc;
  847.     int             nc;
  848.     int             oldstate;
  849.     int             i;
  850.  
  851.     oldstate = State;
  852.     State = NOMAPPING;        /* next characters not mapped */
  853.  
  854.     if (got_int)
  855.     {
  856.         *nextc = NUL;
  857.         return Ctrl('C');
  858.     }
  859.     cc = 0;
  860.     for (i = 0; i < 3; ++i)
  861.     {
  862.         nc = vgetc();
  863.         if (!isdigit(nc))
  864.             break;
  865.         cc = cc * 10 + nc - '0';
  866.         nc = 0;
  867.     }
  868.     if (i == 0)        /* no number entered */
  869.     {
  870.         cc = nc;
  871.         nc = 0;
  872.         if (cc == K_ZERO)    /* NUL is stored as NL */
  873.             cc = '\n';
  874.     }
  875.     else if (cc == 0)        /* NUL is stored as NL */
  876.         cc = '\n';
  877.  
  878.     State = oldstate;
  879.     *nextc = nc;
  880.     got_int = FALSE;        /* CTRL-C typed after CTRL-V is not an interrupt */
  881.     return cc;
  882. }
  883.  
  884. /*
  885.  * Special characters in this context are those that need processing other
  886.  * than the simple insertion that can be performed here. This includes ESC
  887.  * which terminates the insert, and CR/NL which need special processing to
  888.  * open up a new line. This routine tries to optimize insertions performed by
  889.  * the "redo", "undo" or "put" commands, so it needs to know when it should
  890.  * stop and defer processing to the "normal" mechanism.
  891.  */
  892. #define ISSPECIAL(c)    ((c) < ' ' || (c) >= DEL)
  893.  
  894.     void
  895. insertchar(c)
  896.     unsigned    c;
  897. {
  898.     int        haveto_redraw = FALSE;
  899.     int        textwidth;
  900.  
  901.     stop_arrow();
  902.  
  903.     /*
  904.      * find out textwidth to be used:
  905.      *    if 'textwidth' option is set, use it
  906.      *    else if 'wrapmargin' option is set, use Columns - 'wrapmargin'
  907.      *    if invalid value, us 0.
  908.      */
  909.     textwidth = curbuf->b_p_tw;
  910.     if (textwidth == 0 && curbuf->b_p_wm)
  911.         textwidth = Columns - curbuf->b_p_wm;
  912.     if (textwidth < 0)
  913.         textwidth = 0;
  914.  
  915.     /*
  916.      * If the cursor is past 'textwidth' and we are inserting a non-space,
  917.      * try to break the line in two or more pieces. If c == NUL then we have
  918.      * been called to do formatting only. If textwidth == 0 it does nothing.
  919.      * Don't do this if an existing character is being replaced.
  920.      */
  921.     if (c == NUL || !(isspace(c) || (State == REPLACE && *ml_get_cursor() != NUL)))
  922.     {
  923.         while (textwidth && curwin->w_virtcol >= textwidth)
  924.         {
  925.             int        startcol;        /* Cursor column at entry */
  926.             int        wantcol;        /* column at textwidth border */
  927.             int        foundcol;        /* column for start of word */
  928.  
  929.             if ((startcol = curwin->w_cursor.col) == 0)
  930.                 break;
  931.             coladvance(textwidth);            /* find column of textwidth border */
  932.             wantcol = curwin->w_cursor.col;
  933.  
  934.             curwin->w_cursor.col = startcol - 1;
  935.             foundcol = 0;
  936.             while (curwin->w_cursor.col > 0)            /* find position to break at */
  937.             {
  938.                 if (isspace(gchar_cursor()))
  939.                 {
  940.                     while (curwin->w_cursor.col > 0 && isspace(gchar_cursor()))
  941.                         --curwin->w_cursor.col;
  942.                     if (curwin->w_cursor.col == 0)    /* only spaces in front of text */
  943.                         break;
  944.                     foundcol = curwin->w_cursor.col + 1;
  945.                     if (curwin->w_cursor.col < wantcol)
  946.                         break;
  947.                 }
  948.                 --curwin->w_cursor.col;
  949.             }
  950.  
  951.             if (foundcol == 0)            /* no spaces, cannot break line */
  952.             {
  953.                 curwin->w_cursor.col = startcol;
  954.                 break;
  955.             }
  956.             curwin->w_cursor.col = foundcol;        /* put cursor after pos. to break line */
  957.             startcol -= foundcol;
  958.             Opencmd(FORWARD, FALSE, FALSE);
  959.             while (isspace(gchar_cursor()) && startcol)        /* delete blanks */
  960.             {
  961.                 (void)delchar(FALSE);
  962.                 --startcol;                /* adjust cursor pos. */
  963.             }
  964.             curwin->w_cursor.col += startcol;
  965.             curs_columns(FALSE);        /* update curwin->w_virtcol */
  966.             haveto_redraw = TRUE;
  967.         }
  968.         if (c == NUL)                    /* formatting only */
  969.             return;
  970.         if (haveto_redraw)
  971.         {
  972.             /*
  973.              * If the cursor ended up just below the screen we scroll up here
  974.              * to avoid a redraw of the whole screen in the most common cases.
  975.              */
  976.              if (curwin->w_cursor.lnum == curwin->w_botline && !curwin->w_empty_rows)
  977.                 win_del_lines(curwin, 0, 1, TRUE, TRUE);
  978.             updateScreen(CURSUPD);
  979.         }
  980.     }
  981.  
  982.     did_ai = FALSE;
  983.     did_si = FALSE;
  984.     can_si = FALSE;
  985.  
  986.     /*
  987.      * If there's any pending input, grab up to MAX_COLUMNS at once.
  988.      * This speeds up normal text input considerably.
  989.      */
  990.     if (vpeekc() != NUL && State != REPLACE && !p_ri)
  991.     {
  992.         char_u            p[MAX_COLUMNS + 1];
  993.         int             i;
  994.  
  995.         p[0] = c;
  996.         i = 1;
  997.         while ((c = vpeekc()) != NUL && !ISSPECIAL(c) && i < MAX_COLUMNS &&
  998.                     (textwidth == 0 || (curwin->w_virtcol += charsize(p[i - 1])) < textwidth) &&
  999.                     !(!no_abbr && !isidchar(c) && isidchar(p[i - 1])))
  1000.             p[i++] = vgetc();
  1001. #ifdef DIGRAPHS
  1002.         dodigraph(-1);                    /* clear digraphs */
  1003.         dodigraph(p[i-1]);                /* may be the start of a digraph */
  1004. #endif
  1005.         p[i] = '\0';
  1006.         insstr(p);
  1007.         AppendToRedobuff(p);
  1008.     }
  1009.     else
  1010.     {
  1011.         inschar(c);
  1012.         AppendCharToRedobuff(c);
  1013.     }
  1014.  
  1015.     /*
  1016.      * TODO: If the cursor has shifted past the end of the screen, should
  1017.      * adjust the screen display. Avoids extra redraw.
  1018.      */
  1019.  
  1020.     updateline();
  1021. }
  1022.  
  1023. /*
  1024.  * start_arrow() is called when an arrow key is used in insert mode.
  1025.  * It resembles hitting the <ESC> key.
  1026.  */
  1027.     static void
  1028. start_arrow()
  1029. {
  1030.     if (!arrow_used)        /* something has been inserted */
  1031.     {
  1032.         AppendToRedobuff(ESC_STR);
  1033.         arrow_used = TRUE;        /* this means we stopped the current insert */
  1034.         stop_insert();
  1035.     }
  1036. }
  1037.  
  1038. /*
  1039.  * stop_arrow() is called before a change is made in insert mode.
  1040.  * If an arrow key has been used, start a new insertion.
  1041.  */
  1042.     static void
  1043. stop_arrow()
  1044. {
  1045.     if (arrow_used)
  1046.     {
  1047.         u_save_cursor();            /* errors are ignored! */
  1048.         Insstart = curwin->w_cursor;        /* new insertion starts here */
  1049.         ResetRedobuff();
  1050.         AppendToRedobuff((char_u *)"1i");    /* pretend we start an insertion */
  1051.         arrow_used = FALSE;
  1052.     }
  1053. }
  1054.  
  1055. /*
  1056.  * do a few things to stop inserting
  1057.  */
  1058.     static void
  1059. stop_insert()
  1060. {
  1061.     stop_redo_ins();
  1062.  
  1063.     /*
  1064.      * save the inserted text for later redo with ^@
  1065.      */
  1066.     free(last_insert);
  1067.     last_insert = get_inserted();
  1068.     last_insert_skip = new_insert_skip;
  1069.  
  1070.     /*
  1071.      * If we just did an auto-indent, truncate the line, and put
  1072.      * the cursor back.
  1073.      */
  1074.     if (did_ai && !arrow_used)
  1075.     {
  1076.         ml_replace(curwin->w_cursor.lnum, (char_u *)"", TRUE);
  1077.         curwin->w_cursor.col = 0;
  1078.         if (curwin->w_p_list)            /* the deletion is only seen in list mode */
  1079.             updateline();
  1080.     }
  1081.     did_ai = FALSE;
  1082.     did_si = FALSE;
  1083.     can_si = FALSE;
  1084. }
  1085.  
  1086. /*
  1087.  * move cursor to start of line
  1088.  * if flag == TRUE move to first non-white
  1089.  */
  1090.     void
  1091. beginline(flag)
  1092.     int            flag;
  1093. {
  1094.     curwin->w_cursor.col = 0;
  1095.     if (flag)
  1096.     {
  1097.         register char_u *ptr;
  1098.  
  1099.         for (ptr = ml_get(curwin->w_cursor.lnum); iswhite(*ptr); ++ptr)
  1100.             ++curwin->w_cursor.col;
  1101.     }
  1102.     curwin->w_set_curswant = TRUE;
  1103. }
  1104.  
  1105. /*
  1106.  * oneright oneleft onedown oneup
  1107.  *
  1108.  * Move one char {right,left,down,up}.
  1109.  * Return OK when sucessful, FAIL when we hit a line of file boundary.
  1110.  */
  1111.  
  1112.     int
  1113. oneright()
  1114. {
  1115.     char_u *ptr;
  1116.  
  1117.     ptr = ml_get_cursor();
  1118.     if (*ptr++ == NUL || *ptr == NUL)
  1119.         return FAIL;
  1120.     curwin->w_set_curswant = TRUE;
  1121.     ++curwin->w_cursor.col;
  1122.     return OK;
  1123. }
  1124.  
  1125.     int
  1126. oneleft()
  1127. {
  1128.     if (curwin->w_cursor.col == 0)
  1129.         return FAIL;
  1130.     curwin->w_set_curswant = TRUE;
  1131.     --curwin->w_cursor.col;
  1132.     return OK;
  1133. }
  1134.  
  1135.     int
  1136. oneup(n)
  1137.     long n;
  1138. {
  1139.     if (n != 0 && curwin->w_cursor.lnum == 1)
  1140.         return FAIL;
  1141.     if (n >= curwin->w_cursor.lnum)
  1142.         curwin->w_cursor.lnum = 1;
  1143.     else
  1144.         curwin->w_cursor.lnum -= n;
  1145.  
  1146.     if (operator == NOP)
  1147.         cursupdate();                /* make sure curwin->w_topline is valid */
  1148.  
  1149.     /* try to advance to the column we want to be at */
  1150.     coladvance(curwin->w_curswant);
  1151.     return OK;
  1152. }
  1153.  
  1154.     int
  1155. onedown(n)
  1156.     long n;
  1157. {
  1158.     if (n != 0 && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
  1159.         return FAIL;
  1160.     curwin->w_cursor.lnum += n;
  1161.     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  1162.         curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1163.  
  1164.     if (operator == NOP)
  1165.         cursupdate();                /* make sure curwin->w_topline is valid */
  1166.  
  1167.     /* try to advance to the column we want to be at */
  1168.     coladvance(curwin->w_curswant);
  1169.     return OK;
  1170. }
  1171.  
  1172. /*
  1173.  * move screen 'count' pages up or down and update screen
  1174.  *
  1175.  * return FAIL for failure, OK otherwise
  1176.  */
  1177.     int
  1178. onepage(dir, count)
  1179.     int        dir;
  1180.     long    count;
  1181. {
  1182.     linenr_t        lp;
  1183.     long            n;
  1184.  
  1185.     if (curbuf->b_ml.ml_line_count == 1)    /* nothing to do */
  1186.         return FAIL;
  1187.     for ( ; count > 0; --count)
  1188.     {
  1189.         if (dir == FORWARD ? (curwin->w_topline >= curbuf->b_ml.ml_line_count - 1) : (curwin->w_topline == 1))
  1190.         {
  1191.             beep();
  1192.             return FAIL;
  1193.         }
  1194.         if (dir == FORWARD)
  1195.         {
  1196.             if (curwin->w_botline > curbuf->b_ml.ml_line_count)                /* at end of file */
  1197.                 curwin->w_topline = curbuf->b_ml.ml_line_count;
  1198.             else if (plines(curwin->w_botline) >= curwin->w_height - 2 ||    /* next line is big */
  1199.                     curwin->w_botline - curwin->w_topline <= 3)        /* just three lines on screen */
  1200.                 curwin->w_topline = curwin->w_botline;
  1201.             else
  1202.                 curwin->w_topline = curwin->w_botline - 2;
  1203.             curwin->w_cursor.lnum = curwin->w_topline;
  1204.             if (count != 1)
  1205.                 comp_Botline(curwin);
  1206.         }
  1207.         else    /* dir == BACKWARDS */
  1208.         {
  1209.             lp = curwin->w_topline;
  1210.             /*
  1211.              * If the first two lines on the screen are not too big, we keep
  1212.              * them on the screen.
  1213.              */
  1214.             if ((n = plines(lp)) > curwin->w_height / 2)
  1215.                 --lp;
  1216.             else if (lp < curbuf->b_ml.ml_line_count && n + plines(lp + 1) < curwin->w_height / 2)
  1217.                 ++lp;
  1218.             curwin->w_cursor.lnum = lp;
  1219.             n = 0;
  1220.             while (n <= curwin->w_height && lp >= 1)
  1221.             {
  1222.                 n += plines(lp);
  1223.                 --lp;
  1224.             }
  1225.             if (n <= curwin->w_height)                /* at begin of file */
  1226.                 curwin->w_topline = 1;
  1227.             else if (lp >= curwin->w_topline - 2)        /* happens with very long lines */
  1228.             {
  1229.                 --curwin->w_topline;
  1230.                 comp_Botline(curwin);
  1231.                 curwin->w_cursor.lnum = curwin->w_botline - 1;
  1232.             }
  1233.             else
  1234.                 curwin->w_topline = lp + 2;
  1235.         }
  1236.     }
  1237.     beginline(TRUE);
  1238.     updateScreen(VALID);
  1239.     return OK;
  1240. }
  1241.  
  1242.     void
  1243. stuff_inserted(c, count, no_esc)
  1244.     int        c;
  1245.     long    count;
  1246.     int        no_esc;
  1247. {
  1248.     char_u        *esc_ptr = NULL;
  1249.     char_u        *ptr;
  1250.  
  1251.     if (last_insert == NULL)
  1252.     {
  1253.         EMSG("No inserted text yet");
  1254.         return;
  1255.     }
  1256.     if (c)
  1257.         stuffcharReadbuff(c);
  1258.     if (no_esc && (esc_ptr = (char_u *)STRRCHR(last_insert, 27)) != NULL)
  1259.         *esc_ptr = NUL;        /* remove the ESC */
  1260.  
  1261.             /* skip the command */
  1262.     ptr = last_insert + last_insert_skip;
  1263.  
  1264.     do
  1265.         stuffReadbuff(ptr);
  1266.     while (--count > 0);
  1267.  
  1268.     if (no_esc && esc_ptr)
  1269.         *esc_ptr = 27;        /* put the ESC back */
  1270. }
  1271.  
  1272.     char_u *
  1273. get_last_insert()
  1274. {
  1275.     if (last_insert == NULL)
  1276.         return NULL;
  1277.     return last_insert + last_insert_skip;
  1278. }
  1279.  
  1280. /*
  1281.  * Check the word in front of the cursor for an abbreviation.
  1282.  * Called when the non-id character "c" has been entered.
  1283.  * When an abbreviation is recognized it is removed from the text and
  1284.  * the replacement string is inserted in typestr, followed by "c".
  1285.  */
  1286.     static int
  1287. echeck_abbr(c)
  1288.     int c;
  1289. {
  1290.     if (p_paste || no_abbr)            /* no abbreviations or in paste mode */
  1291.         return FALSE;
  1292.  
  1293.     return check_abbr(c, ml_get(curwin->w_cursor.lnum), curwin->w_cursor.col,
  1294.                 curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
  1295. }
  1296.